#include "upgrade.h"
#include "state.h"
#include "event_filters.h"

#include <QDateTime>
#include <QFile>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QTimer>
#include <QToolButton>

/**
 * UpgradeView
 */

UpgradeView::UpgradeView( UpgradeType t, const State & state, QWidget * parent )
    : type( t ) {
    setParent( parent );
    setMinimumWidth( 180 );
    setObjectName( QString::fromStdString( state.getType( type ).getName() ) );
    // workaround to set background colour  to all layout, even for spaces
    background = new QWidget{ this };
    background->setFixedSize( size() );

    QGridLayout * layout = new QGridLayout{ this };
    layout->setSpacing( 3 );

    //  header
    QWidget * header = new QWidget{ this };
    QHBoxLayout * headerLayout = new QHBoxLayout{ header };
    if ( QFile::exists( ":/upgrade/" + objectName() ) )
    {
        QLabel * upgradeIcon = new QLabel{ header };
        upgradeIcon->setPixmap( QPixmap( ":/upgrade/" + objectName() ).scaledToHeight( 24, Qt::SmoothTransformation ) );
        headerLayout->addWidget( upgradeIcon );
    }
    QLabel * upgradeName = new QLabel( objectName(), header );
    upgradeName->setStyleSheet( "QLabel{ font-weight: bold; }" );
    headerLayout->addSpacing( 5 );
    headerLayout->addWidget( upgradeName );

    // level
    level = new QSpinBox{ this };
    level->setStyleSheet( "font-size:14px;" );
    level->setRange( 0, type == UpgradeType::Cost_Reduction_Assets || type == UpgradeType::Cost_Reduction_Orb ? MAXLEVELREDUCTION : MAXLEVEL );
    level->setAlignment( Qt::AlignHCenter );
    level->installEventFilter( new SelectAllOnFocusIn{ this } );
    connect( level, QOverload<int>::of( &QSpinBox::valueChanged ), this, [this]( int i ) { emit levelChanged( type, i ); } );
    connect( level->findChild<QLineEdit *>(), &QLineEdit::returnPressed, level, &QWidget::clearFocus );

    //  buy button
    buy = new QToolButton{ this };
    buy->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
    buy->setAutoRepeat( true );
    buy->setAutoRepeatDelay( 1000 );
    buy->setAutoRepeatInterval( 100 );
    connect( buy, &QToolButton::released, this, &UpgradeView::buyLevels );

    // effect
    QLabel * effectName = new QLabel{ this };
    effectName->setTextFormat( Qt::RichText );
    ProductType priceType = ProductType::XP;
    switch ( type )
    {
        case UpgradeType::SolarPanel:
        case UpgradeType::WindMill:
        case UpgradeType::Reflector:
            priceType = ProductType::Asset;
            effectName->setText( "<center>Production</center>" );
            break;
        case UpgradeType::Effeciency_SolarPanel:
            effectName->setText( "<center>Solar plant<br>multiplier</center>" );
            break;
        case UpgradeType::Effeciency_WindWill:
            effectName->setText( "<center>Wind Mill<br>multiplier</center>" );
            break;
        case UpgradeType::Effeciency_Reflector:
            effectName->setText( "<center>Reflector<br>multiplier</center>" );
            break;
        case UpgradeType::Generator_Asset:
            effectName->setText( "<center>Assets<br>multiplier</center>" );
            break;
        case UpgradeType::Generator_Power:
            effectName->setText( "<center>Power<br>multiplier</center>" );
            break;
        case UpgradeType::Generator_XP:
            effectName->setText( "<center>XP<br>multiplier</center>" );
            break;
        case UpgradeType::Cost_Reduction_Assets:
            effectName->setText( "<center>Total cost<br>reduction</center>" );
            break;
        case UpgradeType::Cost_Reduction_Orb:
            effectName->setText( "<center>Total orb cost<br>reduction</center>" );
            break;
    }
    effect = new QLabel{ this };
    effect->setStyleSheet( "QLabel { font-size: 14px; }" );

    // upgrade cost

    QWidget * priceLabel = new QWidget{ this };
    QHBoxLayout * priceLayout = new QHBoxLayout{ priceLabel };
    priceLayout->setSpacing( 0 );
    priceLayout->setMargin( 0 );
    QLabel * priceName = new QLabel{ priceLabel };
    priceName->setTextFormat( Qt::RichText );
    priceName->setText( "<center>Cost</center>" );
    priceLayout->addWidget( priceName );
    priceLayout->addSpacing( 10 );
    if ( QFile::exists( QString::fromStdString( ":/product/" + state.getType( priceType ).name ) ) )
    {
        QLabel * priceIcon = new QLabel{ priceLabel };
        priceIcon->setPixmap( QPixmap{ QString::fromStdString( ":/product/" + state.getType( priceType ).name ) }.scaledToHeight( 24, Qt::SmoothTransformation ) );
        priceLayout->addWidget( priceIcon );
    }
    price = new QLabel{ this };
    price->setStyleSheet( "QLabel { font-size: 14px; }" );

    //  layout
    layout->addWidget( header, 0, 0, 1, -1, Qt::AlignCenter );
    layout->addWidget( level, 1, 0, Qt::AlignCenter );
    layout->addWidget( buy, 1, 1 );
    layout->addWidget( effectName, 2, 0 );
    layout->addWidget( effect, 2, 1, Qt::AlignJustify );
    layout->addWidget( priceLabel, 3, 0, Qt::AlignRight );
    layout->addWidget( price, 3, 1, Qt::AlignJustify );

    //  set info and connect signals,  slots
    updateData( state );
}

void UpgradeView::updateData( const State & state ) {
    ProductType upType = ProductType::XP;
    level->setValue( static_cast<int>( state.getType( type ).getLevel() ) );
    level->setSingleStep( static_cast<int>( state.getStep( type ) ) );
    switch ( type )
    {
        case UpgradeType::SolarPanel:
        case UpgradeType::WindMill:
        case UpgradeType::Reflector:
            upType = ProductType::Asset;
            effect->setText( QString::number( state.getBasicProduction( type, state.getType( type ).getLevel(), state.getTier() ), 'f', 0 ) );
            break;

        case UpgradeType::Effeciency_SolarPanel:
        case UpgradeType::Effeciency_WindWill:
        case UpgradeType::Effeciency_Reflector:
            effect->setText( QString::number( static_cast<double>( state.getType( type ).getLevel() ) * EFFICIENCY * 100 + 100 ) + " %" );
            break;

        case UpgradeType::Generator_Asset:
        case UpgradeType::Generator_Power:
        case UpgradeType::Generator_XP:
            effect->setText( QString::number( static_cast<double>( state.getType( type ).getLevel() ) * GENERATOR * 100 + 100 ) + " %" );
            break;

        case UpgradeType::Cost_Reduction_Assets:
        case UpgradeType::Cost_Reduction_Orb:
            effect->setText( QString::number( state.getType( type ).getLevel() ) + " %" );
            break;
    }
    if ( level->value() != level->maximum() )
    {
        price->setText( QString::fromStdString( doubleToUnits( state.upgradePrice( type, level->singleStep() ) ) ) );
    } else
        price->setText( "MAXED" );

    // update background
    double priority = state.getType( type ).getPriority();
    //     size_t pos = state.getType( type ).getPosition();
    if ( priority > 0 && level->value() != level->maximum() )
    {
        /// @todo add opacity based on priority?
        //         background->setStyleSheet( "background-color: #" + rgb[pos] + ";" );
        QColor bg = priorityToColour( priority );
        background->setStyleSheet( QString( "background-color: hsva(%1, %2, %3, 75%);" ).arg( bg.hue() ).arg( bg.saturation() ).arg( bg.value() ) );
    } else
    { background->setStyleSheet( "" ); }

    // button
    buy->setEnabled( level->value() != level->maximum() && state.getType( upType ).value > state.upgradePrice( type, state.getStep( type ) ) );
    if ( level->value() != level->maximum() )
    {
        if ( buy->isEnabled() )
        {
            if ( priority == 1 )
            {
                buy->setText( "BUY ME!" );
                buy->setStyleSheet( "font-weight:bold; font-size: 14px;" );
            } else
            {
                buy->setText( "Buy " + QString::number( level->singleStep() ) );
                buy->setStyleSheet( "" );
            }
        } else
        {
            int seconds
                = static_cast<int>( ( state.upgradePrice( type, state.getStep( type ) ) - state.getType( upType ).value ) * 60 / state.getTotalProductionType( upType ) );
            if ( seconds > 0 )
            {
                buy->setText( QDateTime::fromSecsSinceEpoch( seconds, Qt::UTC ).toString( "hh:mm:ss" ) );
                buy->setStyleSheet( "" );
            }
        }
    } else
    { buy->setText( "MAX" ); }
}

void UpgradeView::buyLevels() {
    level->stepUp();
    level->setFocus();
    level->clearFocus();
}

QColor UpgradeView::priorityToColour( double priority ) {
    const QColor begin = QColor::fromHsv( 0, 127, 204 );
    const QColor end = QColor::fromHsv( 90, 127, 204 );
    return QColor::fromHsv( begin.hue() + static_cast<int>( priority * ( end.hue() - begin.hue() ) ),
                            begin.saturation() + static_cast<int>( priority * ( end.saturation() - begin.saturation() ) ),
                            begin.value() + static_cast<int>( priority * ( end.value() - begin.value() ) ) );
}
